﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Nes4Net
{
    public class Tile
    {
        public Int32[] pix;
        private Int32 fbIndex;
        private Int32 tIndex;
        private Int32 x;
        private Int32 y;
        private Int32 w;
        private Int32 h;
        private Int32 incX;
        private Int32 incY;
        private Int32 palIndex;
        private Int32 tpri;
        private Int32 c;
        private Boolean initialized;
        public Boolean[] opaque;

        public Tile() 
        {
            this.pix = new int[64];
            this.opaque = new bool[8];
            this.tIndex = 0;
            this.initialized = false;
        }

        public void SetBuffer(Int32[] scanline)
        {
            for(this.y = 0;this.y < 8; this.y++)
            {
                this.SetScanline(this.y, scanline[this.y], scanline[this.y + 8]);
            }
        }

        public void SetScanline(int sline, int b1, int b2)
        {
            this.initialized = true;
            this.tIndex = sline << 3;
            for (this.x = 0; this.x < 8; this.x++)
            {
                this.pix[this.tIndex + this.x] =
                  ((b1 >> (7 - this.x)) & 1) + (((b2 >> (7 - this.x)) & 1) << 1);
                if (this.pix[this.tIndex + this.x] == 0)
                {
                    this.opaque[sline] = false;
                }
            }
        }

        public void render(
            Int32[] buffer,
            Int32 srcx1,
            Int32 srcy1,
            Int32 srcx2,
            Int32 srcy2,
            Int32 dx,
            Int32 dy,
            Int32 palAdd,
            Int32[] palette,
            Boolean flipHorizontal,
            Boolean flipVertical,
            Int32 pri,
            Int32[] priTable
            )
        {
            if (dx < -7 || dx >= 256 || dy < -7 || dy >= 240)
            {
                return;
            }
            this.w = srcx2 - srcx1;
            this.h = srcy2 - srcy1;

            if (dx < 0)
            {
                srcx1 -= dx;
            }
            if (dx + srcx2 >= 256)
            {
                srcx2 = 256 - dx;
            }

            if (dy < 0)
            {
                srcy1 -= dy;
            }
            if (dy + srcy2 >= 240)
            {
                srcy2 = 240 - dy;
            }

            if (!flipHorizontal && !flipVertical)
            {
                this.fbIndex = (dy << 8) + dx;
                this.tIndex = 0;
                for (this.y = 0; this.y < 8; this.y++)
                {
                    for (this.x = 0; this.x < 8; this.x++)
                    {
                        if (
                          this.x >= srcx1 &&
                          this.x < srcx2 &&
                          this.y >= srcy1 &&
                          this.y < srcy2
                        )
                        {
                            this.palIndex = this.pix[this.tIndex];
                            this.tpri = priTable[this.fbIndex];
                            if (this.palIndex != 0 && pri <= (this.tpri & 0xff))
                            {
                                buffer[this.fbIndex] = palette[this.palIndex + palAdd];
                                this.tpri = (this.tpri & 0xf00) | pri;
                                priTable[this.fbIndex] = this.tpri;
                            }
                        }
                        this.fbIndex++;
                        this.tIndex++;
                    }
                    this.fbIndex -= 8;
                    this.fbIndex += 256;
                }
            }
            else if (flipHorizontal && !flipVertical) 
            {
                this.fbIndex = (dy << 8) + dx;
                this.tIndex = 7;
                for (this.y = 0; this.y < 8; this.y++)
                {
                    for (this.x = 0; this.x < 8; this.x++)
                    {
                        if (
                          this.x >= srcx1 &&
                          this.x < srcx2 &&
                          this.y >= srcy1 &&
                          this.y < srcy2
                        )
                        {
                            this.palIndex = this.pix[this.tIndex];
                            this.tpri = priTable[this.fbIndex];
                            if (this.palIndex != 0 && pri <= (this.tpri & 0xff))
                            {
                                buffer[this.fbIndex] = palette[this.palIndex + palAdd];
                                this.tpri = (this.tpri & 0xf00) | pri;
                                priTable[this.fbIndex] = this.tpri;
                            }
                        }
                        this.fbIndex++;
                        this.tIndex--;
                    }
                    this.fbIndex -= 8;
                    this.fbIndex += 256;
                    this.tIndex += 16;
                }
            }
            else if (flipVertical && !flipHorizontal)
            {
                this.fbIndex = (dy << 8) + dx;
                this.tIndex = 56;
                for (this.y = 0; this.y < 8; this.y++)
                {
                    for (this.x = 0; this.x < 8; this.x++)
                    {
                        if (
                          this.x >= srcx1 &&
                          this.x < srcx2 &&
                          this.y >= srcy1 &&
                          this.y < srcy2
                        )
                        {
                            this.palIndex = this.pix[this.tIndex];
                            this.tpri = priTable[this.fbIndex];
                            if (this.palIndex != 0 && pri <= (this.tpri & 0xff))
                            {
                                buffer[this.fbIndex] = palette[this.palIndex + palAdd];
                                this.tpri = (this.tpri & 0xf00) | pri;
                                priTable[this.fbIndex] = this.tpri;
                            }
                        }
                        this.fbIndex++;
                        this.tIndex++;
                    }
                    this.fbIndex -= 8;
                    this.fbIndex += 256;
                    this.tIndex -= 16;
                }
            }
            else
            {
                this.fbIndex = (dy << 8) + dx;
                this.tIndex = 63;
                for (this.y = 0; this.y < 8; this.y++)
                {
                    for (this.x = 0; this.x < 8; this.x++)
                    {
                        if (
                          this.x >= srcx1 &&
                          this.x < srcx2 &&
                          this.y >= srcy1 &&
                          this.y < srcy2
                        )
                        {
                            this.palIndex = this.pix[this.tIndex];
                            this.tpri = priTable[this.fbIndex];
                            if (this.palIndex != 0 && pri <= (this.tpri & 0xff))
                            {
                                buffer[this.fbIndex] = palette[this.palIndex + palAdd];
                                this.tpri = (this.tpri & 0xf00) | pri;
                                priTable[this.fbIndex] = this.tpri;
                            }
                        }
                        this.fbIndex++;
                        this.tIndex--;
                    }
                    this.fbIndex -= 8;
                    this.fbIndex += 256;
                }
            }
        }

        public Boolean IsTransparent (Int32 x, Int32 y)
        {
            return this.pix[(y << 3) + x] == 0;
        }
    }
}
